﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NativeWifi;
using System.Timers;
using System.Diagnostics;

namespace dotSimpl.wlanner.Logic
{
    /// <summary>
    /// The ConnectionWatcher class watchs for wireless connection and 
    /// fires event, when connection started and connection stopped.
    /// </summary>
    public class ConnectionWatcher
    {
        #region Nested Classes

        /// <summary>
        /// Auxiliary data structure.
        /// </summary>
        private class WatchedInterface
        {
            public Guid guid;
            public bool isAlive;
        }

        #endregion

        #region Fields

        private Timer timer;
        private WlanClient client;
        private bool watching;
        private List<WatchedInterface> watchedIntefaces;

        #endregion

        #region Events

        /// <summary>
        /// This event is fired when adapter connects to the wireless network.
        /// </summary>
        public event EventHandler<ConnectionStateChangedEventArgs> NetworkConnected;

        /// <summary>
        /// This event is fired when adapter disconnects from the wireless network.
        /// </summary>
        public event EventHandler<ConnectionStateChangedEventArgs> NetworkDisconnected;

        #endregion

        #region Constructors

        /// <summary>
        /// Creates a new instance of ConnectionWatcher class.
        /// </summary>
        public ConnectionWatcher()
        {
            watchedIntefaces = new List<WatchedInterface>();
            client = new WlanClient();
            timer = new Timer(1000);
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Enabled = true;
            watching = false;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Starts watching for wireless networks.
        /// </summary>
        public void StartWatching()
        {
            watching = true;
        }

        /// <summary>
        /// Stops watching for wireless networks.
        /// </summary>
        public void StopWatching()
        {
            watching = false;
        }

        private ConnectionStateChangedEventArgs GetEventArgs(Wlan.WlanNotificationData notifyData,
           Wlan.WlanConnectionNotificationData connNotifyData)
        {
            string ssid = connNotifyData.profileName;
            string name = string.Empty;
            Guid guid = notifyData.interfaceGuid;
            foreach (WlanClient.WlanInterface card in client.Interfaces)
            {
                if (card.InterfaceGuid == guid)
                {
                    name = card.InterfaceName;
                }
            }

            return new ConnectionStateChangedEventArgs(ssid, name, guid);
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets true if watching is active.
        /// </summary>
        public bool IsWatching
        {
            get { return watching; }
        }

        #endregion       

        #region Event Handlers

        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            foreach (WlanClient.WlanInterface card in client.Interfaces)
            {                
                WatchedInterface w;
                if ((w = watchedIntefaces.Find(t => t.guid.Equals(card.InterfaceGuid))) != null)
                {
                    w.isAlive = true;
                    continue;
                }
                else
                {
                    watchedIntefaces.Add(new WatchedInterface() { guid = card.InterfaceGuid, isAlive = true });
                    card.WlanConnectionNotification +=
                    new WlanClient.WlanInterface.WlanConnectionNotificationEventHandler(card_WlanConnectionNotification);
                }
            }
            watchedIntefaces.RemoveAll(t => !t.isAlive);
            foreach (WatchedInterface wi in watchedIntefaces)
            {
                wi.isAlive = false;
            }
            Debug.WriteLine("watched: " + watchedIntefaces.Count.ToString());
        }

        void card_WlanConnectionNotification(Wlan.WlanNotificationData notifyData,
            Wlan.WlanConnectionNotificationData connNotifyData)
        {
            if (!watching)
            {
                return;
            }
            if ((int)notifyData.NotificationCode == (int)Wlan.WlanNotificationCodeAcm.ConnectionStart)
            {
                Debug.WriteLine("Started");
                if (NetworkConnected != null)
                {
                    NetworkConnected(this, GetEventArgs(notifyData, connNotifyData));
                }
            }
            if ((int)notifyData.NotificationCode == (int)Wlan.WlanNotificationCodeAcm.Disconnected)
            {
                Debug.WriteLine("Stopped");
                if (NetworkDisconnected != null)
                {
                    NetworkDisconnected(this, GetEventArgs(notifyData, connNotifyData));
                }
            }
        }

        #endregion
    }
}
